/* 
 * Copyright [2018] [Alex/libo(liboware@gmail.com)]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.codex.shiro.handler;

import com.hyts.codex.common.api.IMenuService;
import com.hyts.codex.common.api.IUserRoleService;
import com.hyts.codex.user.bo.MenuBO;
import com.hyts.codex.user.bo.UserRoleBO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.hyts.codex.base.dto.ResultDTO;
import com.hyts.codex.base.vo.ResultVO;
import com.hyts.codex.common.api.IUserService;
import com.hyts.codex.config.DataStatusEnum;
import com.hyts.codex.user.bo.UserBO;
import com.hyts.codex.user.dto.LoginDTO;

import java.util.LinkedList;
import java.util.List;

/** 
 * @author LiBo/Alex
 * @see org.apache.shiro.realm.AuthorizingRealm
 * @since V1.0
 * @version V1.0 
 */
@Slf4j
//@Component
public class CustomRealm extends AuthorizingRealm {
    
    
    @Autowired
    IUserService userService;

    @Autowired
    IUserRoleService userRoleService;

    @Autowired
    IMenuService menuService;

    /* (非 Javadoc)
     * @param principals
     * @return
     * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)  
     * @exception
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("开始权限校验以及授权操作功能服务");
        String userName = (String) principals.getPrimaryPrincipal();
        log.info("操作用户为{}",userName);
        ResultDTO<ResultVO<UserBO>> resultDTO = userService.loadUserIdByUserName(userName);
        List<Long> roleIdList = new LinkedList<>();
        if(resultDTO.isSuccess()){
            ResultDTO<ResultVO<UserRoleBO>> resultVOResultDTO = userRoleService.findRoleDataByUserId(resultDTO.getResult().getData().getId());
            if(CollectionUtils.isEmpty(resultVOResultDTO.getResult().getDataList())){
                return null;
            }else{
                log.info("开始进行对角色进行赋值操作");
                SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
                resultVOResultDTO.getResult().getDataList().stream().forEach(param->{
                    log.info("用户:{}->角色:{}",userName,param.getRoleCode());
                    simpleAuthenticationInfo.addRole(param.getRoleCode());
                    roleIdList.add(param.getRoleId());
                });
                log.info("角色赋值操作完成结束");
                //加载总体个人的权限信息
                ResultDTO<ResultVO<MenuBO>> menuBOList = menuService.findMenuByRoleIds(roleIdList);
                log.info("个人菜单权限加载开始");
                if(menuBOList.isSuccess()){
                    log.info("进行赋值菜单权限功能服务");
                    List<MenuBO> menuBOS = menuBOList.getResult().getDataList();
                    menuBOS.parallelStream().forEach(param->{
                        log.info("用户:{}->菜单:{}->菜单名称:{}",userName,param.getMenuCode(),param.getMenuName());
                        simpleAuthenticationInfo.addStringPermission(param.getMenuCode());
                    });
                }
                log.info("个人菜单权限加载结束");
                log.info("结束权限校验以及授权操作功能服务");
                return simpleAuthenticationInfo;
            }
        }
        return null;
    }

    /* (非 Javadoc)
     * @param token
     * @return
     * @throws AuthenticationException
     * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)  
     * @exception
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户的输入的账号.
        String userName = (String)token.getPrincipal();
        LoginDTO loginDTO = new LoginDTO();
        loginDTO.setUserName(userName);
        ResultDTO<ResultVO<UserBO>> resultDTO = userService.login(loginDTO);
        if(!resultDTO.isSuccess()) {
            throw new UnknownAccountException("不存在此账户或者用户名");//没找到帐号
        }else {
            if(DataStatusEnum.LOCKED.getCode() == resultDTO.getResult().getData().getStatus()) {
                throw new LockedAccountException(DataStatusEnum.LOCKED.getMessage()); //帐号锁定
            }
            String password = resultDTO.getResult().getData().getPassword();
            SimpleAuthenticationInfo authentication = new SimpleAuthenticationInfo(
                    userName,//用户名
                    password,//密码
                    ByteSource.Util.bytes(resultDTO.getResult().getData().getCredentialsSalt()),//加密和填充相关加密salt
                    getName()//区分不同的认证机制
            );
            return authentication;
        }
    }

    /* 
     * @return
     * @see org.apache.shiro.realm.CachingRealm#getName()  
     * @exception
     */ 
    @Override
    public String getName() {
        return "coffice-codex";
    }
}
